﻿using System;
using System.Text;
using PostRequestFactory.Core.Utilities;
using PostRequestFactory.Core.Interfaces;

namespace PostRequestFactory.Core.Parameters
{
    /// <summary>
    /// This class is used for adding binary content to the post request.
    /// BinaryRequestParameter can be used only with requests with multipart/form-data content type.
    /// </summary>
    public class BinaryRequestParameter : IRequestParameter
    {
        private readonly string _contentAsString;
        private readonly byte[] _contentAsBytes;
        private readonly Encoding _initialEncoding; 

        /// <summary>
        /// Content will be provided as base64 string.
        /// Default is false.
        /// </summary>
        public bool TransportAsBase64 { get; private set; }

        /// <summary>
        /// Name of the field/variable to which corresponds the content
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        /// The real name of the file you're uploading
        /// </summary>
        public string FileName { get; private set; }

        /// <summary>
        /// Default value will be application/octet-stream,
        /// but you can set it ta a more specific value like image/gif or other
        /// </summary>
        public string ContentType { get; set; }

        public string ContentDisposition { get { return "form-data"; } }

        /// <summary>
        /// Returns content encoded in base64
        /// </summary>
        public string ContentAsBase64
        {
            get
            {
                if(!TransportAsBase64)
                {
                    throw new ApplicationException("Content cannot be viewed as base64 if the BinaryRequestParameter was marked as non base64 (TransportAsBase64 = false).");  
                }

                return _contentAsString == null ? EncoderUtility.ConvertToBase64(_contentAsBytes) : EncoderUtility.ConvertToBase64(_contentAsString, _initialEncoding ?? Encoding.UTF8);
            }
        }

        /// <summary>
        /// Returns content as an array of bytes
        /// </summary>
        public byte[] ContentAsBytes
        {
            get
            {
                if (TransportAsBase64)
                {
                    throw new ApplicationException("Content cannot be extracted as byte[] if the BinaryRequestParameter was marked as base64 (TransportAsBase64 = true).");
                }

                return _contentAsBytes ?? (_initialEncoding ?? Encoding.UTF8).GetBytes(_contentAsString);
            }
        }

        /// <summary>
        /// Type of the parameter
        /// </summary>
        public RequestParameterType ParameterType
        {
            get { return RequestParameterType.Binary; }
        }

        #region Ctors
        
        /// <summary>
        /// Creates a new instace of the BinaryRequestParameter.
        /// </summary>
        /// <param name="name">Control name.</param>
        /// <param name="content">Control content/value.</param>
        /// <param name="fileName">Name of the uploaded file.</param>
        /// <param name="currentContentEncoding">Encoding used by the current content.</param>
        /// <param name="transportAsBase64">Convert content to base64. Default value is false.</param>
        public BinaryRequestParameter(string name, string content, string fileName, Encoding currentContentEncoding, bool transportAsBase64 = false)
        {
            //set default content type
            ContentType = "application/octet-stream";
            Name = name;
            FileName = fileName;
            TransportAsBase64 = transportAsBase64;
            _contentAsString = content;
            _initialEncoding = currentContentEncoding;
        }

        /// <summary>
        /// Creates a new instace of the BinaryRequestParameter.
        /// </summary>
        /// <param name="name">Control name.</param>
        /// <param name="content">Control content/value.</param>
        /// <param name="transportAsBase64">Convert content to base64. Default value is false.</param>
        public BinaryRequestParameter(string name, string content, bool transportAsBase64 = false)
            : this(name, content, null, null, transportAsBase64)
        {
        }

        /// <summary>
        /// Creates a new instace of the BinaryRequestParameter.
        /// </summary>
        /// <param name="name">Control name.</param>
        /// <param name="content">Control content/value as an array of byte.s</param>
        /// <param name="fileName">Name of the uploaded file.</param>
        /// <param name="transportAsBase64">Convert content to base64. Default value is false.</param>
        public BinaryRequestParameter(string name, byte[] content, string fileName, bool transportAsBase64 = false)
        {
            //set deafult content type
            ContentType = "application/octet-stream";
            Name = name;
            FileName = fileName;
            _contentAsBytes = content;
            TransportAsBase64 = transportAsBase64;
        }

        /// <summary>
        /// Creates a new instace of the BinaryRequestParameter.
        /// </summary>
        /// <param name="name">Control name.</param>
        /// <param name="content">Control content/value as an array of bytes.</param>
        public BinaryRequestParameter(string name, byte[] content)
            : this(name, content, null)
        {
        } 

        #endregion
    }
}
